package com.mazaiting.gateway.security;

import com.mazaiting.gateway.domain.NoTokenBean;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import org.springframework.web.util.pattern.PathPatternParser;
import reactor.core.publisher.Mono;

/**
 * 移除 TOKEN 认证过滤器
 * 认证之前校验 SecurityWebFiltersOrder.AUTHENTICATION
 * 解决 refresh_token 认证失败问题
 * 1. 根据配置的 URL 移除 token, 此处只要不存在 token 就不会校验其有效期
 * @author mazaiting
 * @create_time 2022/8/29 15:35
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class NoTokenAuthorizationFilter implements WebFilter {

    private final NoTokenBean noTokenBean;

    @Override
    @NonNull
    public Mono<Void> filter( ServerWebExchange exchange, @NonNull WebFilterChain chain) {
        // 获取请求路径
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        log.info("=================  No Token 认证过滤 start, url: {} ==================", path);
        // 白名单移除路径信息
        boolean ignoreMatch = noTokenBean.getUrls()
                .stream().anyMatch(s -> PathPatternParser.defaultInstance.parse(s).matches(PathContainer.parsePath(path)));
        if (ignoreMatch) {
            // 移除token信息
            request = exchange.getRequest().mutate().header(HttpHeaders.AUTHORIZATION, "").build();
            exchange = exchange.mutate().request(request).build();
        }
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            log.info("=================  No Token 认证过滤 end, url: {} ==================", path);
        }));
    }
}
